package com.estate.config;

import net.sf.ehcache.CacheException;
import net.sf.ehcache.CacheManager;

import org.apache.shiro.mgt.SecurityManager;
import org.apache.log4j.Logger;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.io.ResourceUtils;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import com.estate.shiro.RetryLimitHashedCredentialsMatcher;
import com.estate.shiro.UserRealm;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;

import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * SpringBoot+shiro权限框架的配置
 * 
 * @author
 */
@Configuration
public class ShiroConfiguration {

	private static final Logger logger = Logger.getLogger(ShiroConfiguration.class);

	/**
	 * shiro 过滤器
	 * @param securityManager
	 * @return
	 */
	@Bean(name = "ShiroFilter")
	public ShiroFilterFactoryBean ShiroFilter(@Qualifier("securityManager") SecurityManager securityManager) {
		System.err.println("--------------shiro 过滤器已经加载----------------");
		// 1.创建ShiroFilterFactoryBean对象
		ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
		// 2.设置SecurityManager;
		shiroFilterFactoryBean.setSecurityManager(securityManager);
		// 3.配置拦截器.使用Map进行配置：LinkedHashMap ，LinkedHashMap是有序的，shiro会根据添加的顺序进行拦截。
		Map<String, String> filterChainMap = new LinkedHashMap<String, String>();

		// 配置退出.过滤器：loginout,这个由shiro进行实现的
		filterChainMap.put("/loginout", "logout");
		// authc : 所有的URL都必须认证通过才可以访问
		// filterChainMap.put("/**","authc");

		// 设置默认登录的URL
		shiroFilterFactoryBean.setLoginUrl("/login");
		// 设置成功之后要跳转的URL路径链接
		shiroFilterFactoryBean.setSuccessUrl("/index");
		// 未授权界面
		shiroFilterFactoryBean.setUnauthorizedUrl("/403");

		shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainMap);

		return shiroFilterFactoryBean;
	}

	/**
	 * shiro安全管理器设置realm认证和ehcache缓存管理
	 * @return
	 */
	@Bean
	public SecurityManager securityManager() {
		DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
		// 设置realm.
		securityManager.setRealm(shiroRealm());
		// //注入ehcache缓存管理器;
		securityManager.setCacheManager(ehCacheManager());
		// 注入Cookie记住我管理器
		securityManager.setRememberMeManager(rememberMeManager());
		return securityManager;
	}	
	
	/**
	 * ehcache缓存管理器；shiro整合ehcache： 通过安全管理器：securityManager 单例的cache防止热部署重启失败
	 * @return EhCacheManager
	 */
	@Bean
	public EhCacheManager ehCacheManager() {
		logger.debug("=====shiro整合ehcache缓存：ShiroConfiguration.getEhCacheManager()");
		EhCacheManager ehcache = new EhCacheManager();
		CacheManager cacheManager = CacheManager.getCacheManager("es");
		if (cacheManager == null) {
			try {
				cacheManager = CacheManager.create(
								ResourceUtils.getInputStreamForPath("classpath:config/ehcache.xml"));
			} catch (CacheException | IOException e) {
				e.printStackTrace();
			}
		}
		ehcache.setCacheManager(cacheManager);
		return ehcache;
	}
	
	/**
	 * 凭证匹配器 （由于我们的密码校验交给Shiro的SimpleAuthenticationInfo进行处理了
	 * 所以我们需要修改下doGetAuthenticationInfo中的代码,更改密码生成规则和校验的逻辑一致即可; 
	 * @return
	 */
	/*@Bean
	public HashedCredentialsMatcher hashedCredentialsMatcher() {
		HashedCredentialsMatcher hashedCredentialsMatcher = new RetryLimitHashedCredentialsMatcher(ehCacheManager());
		//new HashedCredentialsMatcher();
		//hashedCredentialsMatcher.setHashAlgorithmName("md5");// 散列算法:这里使用MD5算法;
		//hashedCredentialsMatcher.setHashIterations(1);// 散列的次数，比如散列两次，相当于  md5(md5(""));
		return hashedCredentialsMatcher;
	}*/
	
	/**
	 * 身份认证realm; (账号密码校验；权限等)
	 * @return
	 */
	@Bean
	public UserRealm shiroRealm() {
		UserRealm shiroRealm = new UserRealm();
		// 使用自定义的CredentialsMatcher进行密码校验和输错次数限制
		//shiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());
		return shiroRealm;
	}

	/**
	 * 设置记住我cookie过期时间
	 * @return
	 */
	@Bean
	public SimpleCookie remeberMeCookie() {
		logger.debug("记住我，设置cookie过期时间！");
		// cookie名称;对应前端的checkbox的name = rememberMe
		SimpleCookie scookie = new SimpleCookie("rememberMe");
		// 记住我cookie生效时间30天 ,单位秒 [1小时]
		scookie.setMaxAge(3600);
		return scookie;
	}

	/**
	 * 配置cookie记住我管理器
	 * @return
	 */
	@Bean
	public CookieRememberMeManager rememberMeManager() {
		logger.debug("配置cookie记住我管理器！");
		CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
		cookieRememberMeManager.setCookie(remeberMeCookie());
		return cookieRememberMeManager;
	}

	

	/**
	 * @描述：ShiroDialect，为了在thymeleaf里使用shiro的标签的bean
	 * @return
	 */
	@Bean
	public ShiroDialect shiroDialect() {
		return new ShiroDialect();
	}

}
